package com.demo.petshop.service.impl;

import com.demo.petshop.entity.UserStatsDTO;
import com.demo.petshop.entity.Users;
import com.demo.petshop.mapper.FavoritesMapper;
import com.demo.petshop.mapper.UsersMapper;
import com.demo.petshop.service.UsersService;
import com.demo.petshop.util.JwtUtil;
import com.demo.petshop.util.Result;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.sqlite.date.DateFormatUtils;

import java.util.Date;
import java.util.Map;

import static com.demo.petshop.entity.table.FavoritesTableDef.FAVORITES;
import static com.demo.petshop.entity.table.UsersTableDef.USERS;

/**
 *  服务层实现。
 *
 * @author lenovo
 * @since 2025-06-11
 */
@Service
public class UsersServiceImpl extends ServiceImpl<UsersMapper, Users> implements UsersService {
    @Autowired
    private UsersMapper usersMapper;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private FavoritesMapper favoritesMapper;

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    private String updateAt = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");

    @Override
    public Users loginByEmail(String email, String password) {
        Users user = usersMapper.selectOneByQuery(new QueryWrapper().where(USERS.EMAIL.eq(email)));
        if (user != null && passwordEncoder.matches(password, user.getPasswordHash())) {
            return user;
        }
        return null;
    }

    @Override
    public Users getUserByEmail(String email) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.where(USERS.EMAIL.eq(email));
        return usersMapper.selectOneByQuery(queryWrapper);
    }

    @Override
    public Object updateprofile(Users users) {
        users.setUpdatedAt(updateAt);
        users.setUserId(getUserId());
        return usersMapper.update(users);
    }

    private int getUserId() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        return loginUser.getUser().getUserId();
    }

    @Override
    public Object login(Users users) {
        Users user = usersMapper.selectOneByQuery(
                new QueryWrapper()
                        .where(USERS.USERNAME.eq(users.getUsername()))
                        .or(USERS.PHONE.eq(users.getUsername()))
                        .or(USERS.EMAIL.eq(users.getUsername()))
        );
        users.setUsername(user.getUsername());
        if(Integer.parseInt(user.getMemberLevel()) < 0){
            return Result.fail("该用户无权访问客户端");
        }
        UsernamePasswordAuthenticationToken authenticationToken  =
                new UsernamePasswordAuthenticationToken(users.getUsername(), users.getPasswordHash());
        Authentication auth = authenticationManager.authenticate(authenticationToken);
        LoginUser loginUser = (LoginUser) auth.getPrincipal();
        Users ret = loginUser.getUser();
        ret.setPasswordHash(JwtUtil.generateToken(ret));
        return Result.success(ret);
    }

    @Override
    public Object loginAdmin(Users users) {
        Users user = usersMapper.selectOneByQuery(
                new QueryWrapper()
                        .where(USERS.USERNAME.eq(users.getUsername()))
                        .or(USERS.PHONE.eq(users.getUsername()))
                        .or(USERS.EMAIL.eq(users.getUsername()))
        );
        users.setUsername(user.getUsername());
        if(Integer.parseInt(user.getMemberLevel()) > 0){
            return Result.fail("该用户不是管理员");
        }
        UsernamePasswordAuthenticationToken authenticationToken  =
                new UsernamePasswordAuthenticationToken(users.getUsername(), users.getPasswordHash());
        Authentication auth = authenticationManager.authenticate(authenticationToken);
        LoginUser loginUser = (LoginUser) auth.getPrincipal();
        Users ret = loginUser.getUser();
        ret.setPasswordHash(JwtUtil.generateToken(ret));
        return Result.success(ret);
    }

    @Override
    public Object checkMemberLevel() {
        return Result.success(usersMapper.selectOneById(getUserId()).getMemberLevel());
    }

    @Override
    public Object register(Users user) {
        if(usersMapper.selectOneByQuery(new QueryWrapper()
                .where(USERS.PHONE.eq(user.getPhone()))) != null){
            return Result.fail("手机号已被注册");
        }
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        user.setPasswordHash(encoder.encode(user.getPasswordHash()));
        user.setCreatedAt(updateAt);
        user.setUpdatedAt(updateAt);
        user.setMemberLevel("0");
        user.setMemberPoints(0);
        return Result.success(usersMapper.insert(user));
    }

    @Override
    public Object updatePassword(Map<String, Object> passwordData) {
        Users user = usersMapper.selectOneById(getUserId());
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        user.setPasswordHash(encoder.encode(passwordData.get("password").toString()));
        return Result.success(usersMapper.update(user));
    }

    @Override
    public Object checkLog() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        Users ret = loginUser.getUser();
        ret.setPasswordHash(JwtUtil.generateToken(ret));
        return Result.success(ret);
    }

    @Override
    public Object getProfile(Integer userId) {
        return usersMapper.selectOneById(userId);
    }

    @Override
    public Object updateSettings(Map<String, Object> settingsData) {
        try {
            Users userToUpdate = getUserForUpdate(settingsData);
            if (userToUpdate == null) {
                return Result.fail("用户不存在");
            }

            boolean hasUpdates = applySettings(settingsData);

            // 如果有更新，则设置更新时间并保存
            if (hasUpdates) {
                userToUpdate.setUpdatedAt(updateAt);
                usersMapper.update(userToUpdate);
            }

            return Result.success("设置更新成功");
        } catch (Exception e) {
            return Result.fail("设置更新失败: " + e.getMessage());
        }
    }

    /**
     * 根据传入的设置数据，获取待更新的用户实体
     */
    private Users getUserForUpdate(Map<String, Object> settingsData) {
        Integer userId;
        // 如果前端传递了userId，则优先使用
        if (settingsData.containsKey("userId")) {
            userId = Integer.valueOf(settingsData.get("userId").toString());
        } else {
            // 否则，从安全上下文中获取当前登录用户的ID
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            LoginUser loginUser = (LoginUser) authentication.getPrincipal();
            userId = loginUser.getUser().getUserId();
        }
        return usersMapper.selectOneById(userId);
    }

    /**
     * 应用所有设置项，并返回是否有任何更新
     */
    private boolean applySettings(Map<String, Object> settingsData) {
        java.util.concurrent.atomic.AtomicBoolean hasUpdates = new java.util.concurrent.atomic.AtomicBoolean(false);

        // 统一处理所有设置项
        applySetting(settingsData, "use_biometric", value -> hasUpdates.set(true));

        applySetting(settingsData, "biometric_type", value -> hasUpdates.set(true));

        applySetting(settingsData, "notifications_enabled", value -> hasUpdates.set(true));

        return hasUpdates.get();
    }


    /**
     * 辅助方法：如果设置项存在，则应用它
     * @param settingsData 数据Map
     * @param key          设置项的键
     * @param action       要执行的操作
     */
    private void applySetting(Map<String, Object> settingsData, String key, java.util.function.Consumer<Object> action) {
        if (settingsData.containsKey(key)) {
            action.accept(settingsData.get(key));
        }
    }


    @Override
    public Object stats() {
        UserStatsDTO userStatsDTO = new UserStatsDTO();
        int userId = getUserId();
        userStatsDTO.setStoreFavorites((int) favoritesMapper.selectCountByQuery(new QueryWrapper()
                .where(FAVORITES.USER_ID.eq(userId))
                .and(FAVORITES.TYPE.eq("store"))));
        userStatsDTO.setProductFavorites((int) favoritesMapper.selectCountByQuery(new QueryWrapper()
                .where(FAVORITES.USER_ID.eq(userId))
                .and(FAVORITES.TYPE.eq("product"))));
        userStatsDTO.setVideoFavorites((int) favoritesMapper.selectCountByQuery(new QueryWrapper()
                .where(FAVORITES.USER_ID.eq(userId))
                .and(FAVORITES.TYPE.eq("video"))));
        userStatsDTO.setPoints(usersMapper.selectOneById(userId).getMemberPoints());
        return Result.success(userStatsDTO);
    }

    @Override
    public Object registerShopkeeper(Users user) {
        if(usersMapper.selectOneByQuery(new QueryWrapper()
                .where(USERS.PHONE.eq(user.getPhone()))) != null){
            return Result.fail("手机号已被注册");
        }
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        user.setPasswordHash(encoder.encode(user.getPasswordHash()));
        user.setCreatedAt(updateAt);
        user.setUpdatedAt(updateAt);
        user.setMemberLevel("-1");
        user.setMemberPoints(0);
        return Result.success(usersMapper.insert(user));
    }
}
